package org.porridge.util;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.porridge.po.EntityPo;
import org.porridge.po.RecordSubmit;
import org.porridge.po.Resource;
import org.porridge.po.SeachLog;
import org.tmatesoft.svn.core.ISVNLogEntryHandler;
import org.tmatesoft.svn.core.SVNDirEntry;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNLogEntry;
import org.tmatesoft.svn.core.SVNLogEntryPath;
import org.tmatesoft.svn.core.SVNNodeKind;
import org.tmatesoft.svn.core.SVNProperties;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.wc.SVNWCUtil;

/**
 * 
 * <p>Title: SVNManager   </p>
 * <p>Description: SVN操作工具类</p>
 * <p>Copyright: Copyright (c) 2012</p>
 * <p>Company: svnkit</p>
 * <p>Create Date/Time: 2014年8月12日 下午8:34:09<p>
 * @author porridge
 * @version 1.0
 * @url www.prdblog.com
 * 此类参考：http://xiangxji.iteye.com/blog/854773
 */
public class SVNManager{

	private SVNRepository repository;
	private String delPath=null;
	public EntityPo po=null;
	
    /**
     * 初始化登录操作
     * @throws Exception
     */
    public boolean initialize(EntityPo po){
    	boolean bl=false;
		FSRepositoryFactory.setup();
		DAVRepositoryFactory.setup();
		SVNRepositoryFactoryImpl.setup();
		try {
			repository = SVNRepositoryFactoryImpl.create(SVNURL.parseURIEncoded(po.getSvn()));
			ISVNAuthenticationManager authManager = SVNWCUtil.createDefaultAuthenticationManager(po.getUsername(),po.getPassword());
			repository.setAuthenticationManager(authManager);
			Collection<SVNDirEntry> entries = repository.getDir("",-1,null,(Collection) null);
			this.po=po;
			bl=true;
		}catch (SVNException e){
			e.printStackTrace();
		}
		return bl;
		
	}
    
	/**
	 * 从SVN服务器获取文件
	 * @param filePath 相对于仓库根目录的路径
	 * @param outputStream 要输出的目标流，可以是文件流 FileOutputStream
	 * @param version 要checkout的版本号
	 * @return 返回checkout文件的版本号
	 * @throws Exception 可以自定义Exception
	 */
    public long getFileFromSVN(String filePath, OutputStream outputStream,long version) throws Exception {
		SVNNodeKind node = null;
		try {
			node=repository.checkPath(filePath,version);
		} catch (SVNException e) {
			throw new Exception("SVN检测不到该文件:" + filePath, e);
		}
		if (node != SVNNodeKind.FILE){
			throw new Exception(node.toString() + "不是文件");
		}
		SVNProperties properties = new SVNProperties();
		try {
			repository.getFile(filePath,version,properties,outputStream);
		} catch (SVNException e) {
			throw new Exception("获取SVN服务器中的" + filePath + "文件失败", e);
		}
		return Long.parseLong(properties.getStringValue("svn:entry:revision"));
	}
    /**
     * 获取目录下的所有文件和子目录
     * 暂时未使用到...
     */
	public List<Resource> getChildren(Resource res) throws Exception {
		String path = res.getPath();
		Collection<SVNDirEntry> entries;
		try {
			entries = repository.getDir(path,-1,null,(Collection) null);
		} catch (SVNException e) {
			throw new Exception("获得" + path + "下级目录失败", e);
		}
		List<Resource> result = new ArrayList<Resource>();
		
		for (SVNDirEntry entry : entries) {
			Resource resource = new Resource();
			resource.setName(entry.getName());
			resource.setPath(entry.getURL().getPath());
			resource.setFile(entry.getKind() == SVNNodeKind.FILE);
			resource.setSVNVersion(entry.getRevision());
			result.add(resource);
		}
		return result;
	}
    /**
     * 查询提交日志
     * @param first
     * @param last
     * @param author
     * @throws Exception
     */
    public List<Resource> filterCommitLog(final SeachLog seach) throws Exception {
        // 过滤条件
    	final List<Resource> res=new ArrayList<Resource>();
        final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        
        //开始时间
        final Date begin =(seach.getDatefirst()!=null && seach.getDatefirst().trim().length()>0)?format.parse(seach.getDatefirst()):null;
        //结束时间
        final Date end =(seach.getDatelast()!=null && seach.getDatelast().trim().length()>0)?format.parse(seach.getDatelast()):null;
        
        
        long startRevision = 0;
        long endRevision = -1;//表示最后一个版本
        repository.log(new String[]{""},startRevision,endRevision,true,true,
                       new ISVNLogEntryHandler() {
                           public void handleLogEntry(SVNLogEntry svnlogentry)
                                   throws SVNException {
                        	   //依据提交时间进行过滤
                               if(verify(seach,svnlogentry))
                            	   fillResult(svnlogentry,res);
                           }
                           /**
                            * 验证数据
                            *  * 查询组合条件一    时间范围限制
							 * 查询组合条件二    版本号限制
							 * 查询组合条件三    多上传人过滤    如果有做限制上传人  在前后加;    ;admin;mast;  用indexOf(";admin;")  才能实现多用户判断
                            * @return
                            */
                           public boolean verify(SeachLog seach,SVNLogEntry svnlogentry){
                        	   boolean bl=true;
                        	   if(svnlogentry.getAuthor()==null)
                        		   bl=false;
                        	   if(!(bl && (begin==null || svnlogentry.getDate().after(begin))))
                        		   bl=false;
                        	   if (!(bl && (end==null || svnlogentry.getDate().before(end)))){
                                   bl=false;
                               }
                        	   
                        	   int vf=-1;//版本号开始
                        	   int vl=-1;//版本号结束
                        	   if(seach.getVersionsfirst()!=null && seach.getVersionsfirst().matches("\\d*"))
                        		   vf=Integer.valueOf(seach.getVersionsfirst());
                        	   if(seach.getVersionslast()!=null && seach.getVersionslast().matches("\\d*"))
                        		   vl=Integer.valueOf(seach.getVersionslast());
                        	   
                        	   if(bl){
	                        	   if(vf!=-1 && vf>svnlogentry.getRevision())
	                        		   bl=false;
	                        	   if(vl!=-1 && vl<svnlogentry.getRevision())
	                        		   bl=false;
                        	   }
                               if (seach.getUsername()!=null && !"".equals(seach.getUsername())) {
                                   if (seach.getUsername().indexOf(";"+svnlogentry.getAuthor()+";")==-1) {//支持多用户过滤查询
                                	   bl=false;
                                   }
                               }
                        	   return bl;
                           }
                           /**
                            * 添加数据  
                            * res 是引用传递
                            */
                           public void fillResult(SVNLogEntry log,List<Resource> res) {
                        	   SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm ss");
                        	   Resource resource=new Resource();
                        	   resource.setSVNVersion(log.getRevision());//版本号
                        	   resource.setSubmituser(log.getAuthor());//提交人
                        	   resource.setSubmittime(sdf.format(log.getDate()));//提交时间
                        	   resource.setRemark(log.getMessage());//提交注释
                        	   
                        	   Map<String,SVNLogEntryPath> map=log.getChangedPaths();
                        	   Set<Map.Entry<String,SVNLogEntryPath>> lv=map.entrySet();//这里是生成键和映射关系的视图    不需要再get一次。所以效率明显快
                        	   List<RecordSubmit> recs=new ArrayList<RecordSubmit>();
                        	   for(Map.Entry<String,SVNLogEntryPath> l:lv){
                        		   if(seach.getSeachfile()==null || l.getKey().indexOf(seach.getSeachfile())==0){
                        			   RecordSubmit r=new RecordSubmit();
                        			   r.setPath(l.getKey());
                        			   r.setType(l.getValue().getType()+"");//A 指添加数据   D 指删除数据   M指修改数据
                        			   recs.add(r);
                        		   }
                        	   }
                        	   resource.setRes(recs);
                        	   res.add(resource);
                           }
             		});
			return res;
    }
    
    
    /**
     * 判断文件是否存在
     * @param entry 要判断的节点.参加{@link SVNDirEntry}
     * 递归取下一级的数据
     * @return 
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
	private boolean containsSpecialFile(SVNDirEntry entry) throws Exception {
		if (entry.getKind() == SVNNodeKind.FILE) {
			return true;
		} else if (entry.getKind() == SVNNodeKind.DIR){
			Collection<SVNDirEntry> entries;
			String path = entry.getURL().getPath();
			try {
				entries = repository.getDir(path.replace(delPath,""),-1,null,(Collection)null);
			} catch (SVNException e) {
				throw new Exception("获得" + path + "*****下级目录失败",e);
			}
			for (SVNDirEntry unit : entries) {
				if(containsSpecialFile(unit)){
					return true;
				}
			}
			return false;
		}
		return false;
	}

}








		

